#coding=utf-8

import sys
import logging
import re
import time
import urllib
import random
import uuid

from datetime import datetime

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.api import memcache

from icalendar import Calendar, Event
from icalendar import UTC
from lunarcalendar.lunarcalendar import *

from utils import util
from utils import page

gen_key_name = lambda s: 'kn' + uuid.uuid3(uuid.NAMESPACE_URL, util.encode_str(s)).get_hex()

#http://feeds.feedburner.com/~r/AppEngineFan/~3/310349458/efficient-global-counters.html
class ShardCounter(db.Model):
    name = db.StringProperty(required=True)
    count = db.IntegerProperty(default=0)
    
    @classmethod
    def get_count(cls, nameOfCounter):
        memcache_id = '/ShardCounter/%s' %  nameOfCounter
        result = memcache.get(memcache_id)
        if not (result == None):
            return result
        result = 0
        for shard in cls.gql('WHERE name=:1', nameOfCounter):
            result += shard.count
        memcache.set(memcache_id, result, 60)
        return result
    @classmethod
    def update_count(cls, nameOfCounter, delta):
        memcache_id = '/ShardCounter/%s' %  nameOfCounter
        memcache.delete(memcache_id)
        shard_id = '/%s/%s' % (nameOfCounter, random.randint(1, _SHARDS_PER_COUNTER))
        def update():
            shard = cls.get_by_key_name(shard_id)
            if shard:
                shard.count += delta
            else:
                shard = cls(key_name=shard_id, name=nameOfCounter, count=delta)
            shard.put()
        db.run_in_transaction(update)

class Account(db.Model):
    
    user         = db.UserProperty(required=True)
    email        = db.EmailProperty(required=True)  # key == <email>
    nickname     = db.StringProperty()
    created      = db.DateTimeProperty(auto_now_add=True)
    modified     = db.DateTimeProperty(auto_now=True)
    access_count = db.IntegerProperty(default = 0)

    @classmethod
    def get_account_for_user(cls, user):
        """Get the Account for a user, creating a default one if needed."""
        email = user.email()
        assert email
        key = '<%s>' % email
        nickname = user.nickname()
        if '@' in nickname:
            nickname = nickname.split('@', 1)[0]
        assert nickname
        return cls.get_or_insert(key, user=user, email=email, nickname=nickname)

    @classmethod
    def get_account_for_email(cls, email):
        """Get the Account for an email address, or return None."""
        assert email
        key = '<%s>' % email
        return cls.get_by_key_name(key)
    
    @classmethod
    def get_current_account(cls):
        usr = users.get_current_user()
        return Account.get_account_for_user(usr)
    
    @property
    def is_admin(self):
        return users.is_current_user_admin()
    
    @property
    def is_sign_in(self):
        return not self.email == 'anonymous@gmail.com' 

################################################################

_ICAL_PRODID = '-//Google Inc//Google Calendar 70.9054//EN'
_ICAL_VERSION = '2.0'
class CalInfo(db.Model):
    summary              = db.StringProperty()
    lunar_birthday_str   = db.StringProperty
    location             = db.StringProperty()
    description          = db.StringProperty()
    start_year           = db.IntegerProperty()
    end_year             = db.IntegerProperty()
    ics_content          = db.TextProperty()     #生成的ics文件的内容
    add_time             = db.DateTimeProperty(auto_now_add=True)
    update_time          = db.DateTimeProperty(auto_now=True)
    owner                = db.ReferenceProperty(Account, collection_name='calendars')
    
    def create_cal_ics(self):
        cal = Calendar()
        cal.add('prodid', _ICAL_PRODID)
        cal.add('version', _ICAL_VERSION)
        lunarCal = LunarCalendar()
        [y, m, d] = self.lunar_birthday_str.split('-')
        for i in range(self.start_year, self.end_year):
            (s_y, s_m, s_d) = lunarCal.getSolarDate(int(i), int(m), int(d))
            event = Event()
            event.add('summary', self.summary)
            event.add('dtstart', datetime(s_y, s_m, s_d, tzinfo=UTC))
            event.add('dtend', datetime(s_y, s_m, s_d, tzinfo=UTC))
            event.add('dtstamp', datetime(s_y, s_m, s_d, tzinfo=UTC))
            event.add('location', self.location)
            event.add('description', self.description)
            cal.add_component(event)
        cal_str = cal.as_string()
        self.ics_content = unicode(cal_str, 'utf-8')
        self.save();
        return cal_str

###########################################################
class ReaderUser(db.Model):
    gr_user_id     = db.StringProperty()
    email          = db.StringProperty()
    liking_items   = db.StringListProperty()
    shared_items   = db.StringListProperty()

class ReaderSharedFeed(db.Model):
    feed_url        = db.StringProperty()
    feed_owner_id   = db.StringProperty()     
    feed_owner_email= db.StringProperty()    # ownder's google account
    last_fetch_time = db.DateTimeProperty()

class ReaderFeedEntry(db.Model):
    gr_id            = db.StringProperty()
    gr_crawl_time    = db.DateTimeProperty()
    gr_linking_users = db.StringListProperty()
    gr_origional_id  = db.StringProperty()
    category         = db.StringProperty()
    title            = db.StringProperty()
    published        = db.DateTimeProperty()
    updated          = db.DateTimeProperty()
    link             = db.StringProperty()
    content          = db.TextProperty()
    authors          = db.StringListProperty()
    source_url       = db.StringProperty()
    score            = db.IntegerProperty()
    feed             = db.ReferenceProperty(ReaderSharedFeed, collection_name='entries')

######################################################################

class AccountBook(db.Model):
    pass

class Transaction(db.Model):
    type         = db.StringProperty(default='INCOME', choices=['INCOME', 'EXPENSE'])
    description  = db.TextProperty()
    amount       = db.IntegerProperty()
    date         = db.DateTimeProperty()
    payment_mode = db.StringProperty(default='CASH', choices=['CASH', 'CARD'])
    repeat       = db.BooleanProperty(default=False)
    
class Budget(db.Model):
    pass

#######################################################################

class TaskList(db.Model):
    pass

class Task(db.Model):
    pass
